﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace ReporterApplication
{
    public sealed class XmlCIF
    {
        public XDocument xd = new XDocument();

        public readonly Dictionary<string, XElement> IDs = new Dictionary<string, XElement>();
        public readonly Dictionary<string, List<XElement>> REFs = new Dictionary<string, List<XElement>>();

        public readonly Dictionary<string, XElement> setLabelList = new Dictionary<string, XElement>();

        public readonly List<pType> pTypes = new List<pType>();

        public static string DateFormat = "dd:MM:YYYY";


        public XElement Notebook;
        public DateTime modifyTime;

        public static int Progress;
        public static string ProgressStep;

        public static XmlCIF Load(string path)
        {
            Progress = 0;

            XmlCIF result = new XmlCIF();
            result.xd = XDocument.Load(path, LoadOptions.SetLineInfo);

            Progress = 2;

            var idels = result.xd.Descendants().Where(x => x.Attribute("id") != null);
            foreach (var idel in idels)
            {
                if (idel.Attribute("id").Value != "")
                    result.IDs.Add(idel.Attribute("id").Value, idel);
            }

            Progress = 4;

            var refels = result.xd.Descendants().Where(x => x.Attribute("refid") != null);
            foreach (var idel in refels)
            {
                var refid = idel.Attribute("refid").Value;
                List<XElement> lis = null;

                if (!result.REFs.ContainsKey(refid))
                {
                    lis = new List<XElement>();
                    result.REFs.Add(refid, lis);
                }
                else
                    lis = result.REFs[refid];


                lis.Add(idel);
            }

            Progress = 5;

            //prepare element types
            var elements = result.xd.Element("cif").Element("notebook").Element("instances")
                .Elements().Where(x => x.Attribute("setLabel") != null);

            foreach (var item in elements)
            {
                var elTypeLabel = item.Attribute("setLabel").Value.ToLower();

                result.setLabelList.Add(elTypeLabel, item);
            }

            //set root for notebook
            result.Notebook = result.xd.Element("cif").Element("notebook");

            //set numbering

            Progress = 7;

            result.modifyTime = result.xd.Descendants("modifyTime")
                .Select(x => DateTime.Parse(x.Value)).Max();

            Progress = 8;

            //prepare metadata model


         //   Progress = 10;

            return result;
        }

        public void PrepareMetadataModel()
        {
            //prepare element types
            var elements = xd.Element("cif").Element("notebook").Element("instances")
                .Elements().Where(x => x.Attribute("setLabel") != null);

            foreach (var item in elements)
            {
                var elTypeLabel = item.Attribute("setLabel").Value.ToLower();

                pType ptype = new pType();
                ptype.Label = item.Attribute("label").Value;
                ptype.setLabel = item.Attribute("setLabel").Value;
                ptype.Count = item.Elements().Count();
                ptype.Command = "$" + item.Attribute("setLabel").Value;

                ptype.Elements = item.Elements().ToList();

                //set attributes
                foreach (var attrib in item.Attributes())
                {
                    if (!ptype.Attributes.Exists(x => x.Name == attrib.Name.LocalName))
                        ptype.Attributes.Add(new NameCount { Name = attrib.Name.LocalName, Count = 1, Command = "#" + attrib.Name.LocalName });
                    else
                        ptype.Attributes.Where(x => x.Name == attrib.Name.LocalName).First().Count++;
                }

                foreach (var elem in item.Elements().Elements())
                {
                    if (elem.Name.LocalName != "createTime"
                        && elem.Name.LocalName != "modifyTime"
                        && elem.Attribute("refid") == null)
                    {
                        if (!ptype.Attributes.Exists(x => x.Name == elem.Name.LocalName))
                            ptype.Attributes.Add(new NameCount { Name = elem.Name.LocalName, Count = 1, Command = "#" + elem.Name.LocalName });
                        else
                            ptype.Attributes.Where(x => x.Name == elem.Name.LocalName).First().Count++;
                    }
                }

                foreach (var elem in item.Elements().Elements())
                {
                    if (elem.Name.LocalName != "createTime"
                        && elem.Name.LocalName != "modifyTime"
                        && elem.Attribute("refid") != null)
                    {
                        //combine name
                        string name = elem.Name.LocalName;
                        string command = "#" + elem.Name.LocalName;
                        string refid = elem.Attribute("refid").Value;

                        if (IDs.ContainsKey(refid))
                        {
                            var idElem = IDs[refid];

                            if (idElem.Parent != null && idElem.Parent.Attribute("label") != null)
                            {
                                name += "(" + idElem.Parent.Attribute("label").Value + ")";
                                command += "$" + idElem.Parent.Attribute("setLabel").Value;
                            }
                            else
                            {
                                //log warning that element is not owned by provision type
                                //and dont have label
                            }
                        }

                        if (!ptype.Referencies.Exists(x => x.Name == name))
                            ptype.Referencies.Add(new NameCount { Name = name, Count = 1, Command = command });
                        else
                            ptype.Referencies.Where(x => x.Name == name).First().Count++;
                    }
                }

                 foreach (var elem in item.Elements())
                {
                    if (elem.Attribute("id") != null)
                    {
                        //get used by elements
                        string id = elem.Attribute("id").Value;

                        if (REFs.ContainsKey(id))
                        {
                            foreach (var elemElement in REFs[id])
                            {
                                var curelem = elemElement.Parent;

                                //if(curelem.Attribute("id") == null)
                                //    curelem = curelem.Parent;

                                string name = "+" + elemElement.Name.LocalName;
                                var command = "+" + elemElement.Name.LocalName;

                                var parent = curelem.Parent;

                                while (parent != null && parent.Attribute("label") == null)
                                {
                                    parent = parent.Parent;
                                }

                                if (parent != null)
                                {
                                    name += "(" + parent.Attribute("label").Value + ")";
                                    command += "$" + parent.Attribute("setLabel").Value;
                                }

                                if (!ptype.UsedBy.Exists(x => x.Name == name))
                                    ptype.UsedBy.Add(new NameCount { Name = name, Count = 1, Command = command });
                                else
                                    ptype.UsedBy.Where(x => x.Name == name).First().Count++;
                            }
                        }
                    }
                }


                pTypes.Add(ptype);
            }
        }

        public IEnumerable<XElement> getBySetLabel(string label)
        {
            label = label.ToLower();

            if (setLabelList.ContainsKey(label))
            {
                List<XElement> filteredList = setLabelList[label].Elements().ToList();

                //filteredList = filteredList.OrderByDescending(x => x.Element("numberPrefix") != null ? x.Element("numberPrefix").Value : x.Attribute("name").Value).ToList();

                //filteredList = filteredList.OrderBy(x => x.Element("numberPrefix") != null ? numberPrefix(x) : x.Attribute("name").Value).ToList();
                filteredList = filteredList.OrderByDescending(x => getFullName(x)).ToList();


                return filteredList;
            }

            return new List<XElement>();
        }

        void getAllUsages(int level,int maxLevel, XElement element, List<XElement> result)
        {
            if (level >= maxLevel)
                return;
            
            //get childs

            foreach (var xel in element.Elements().Where(x => x.Attribute("refid") != null))
            {
                var id = xel.Attribute("refid").Value;

                if (IDs.ContainsKey(id))
                {
                    var curel = IDs[id];

                    if (!result.Contains(curel))
                    {
                        result.Add(curel);

                        getAllUsages(level++, maxLevel, curel, result);
                    }
                }
            }

            //get by refid
            if (element.Attribute("id") != null)
            {
                var id = element.Attribute("id").Value;

                if (REFs.ContainsKey(id))
                {
                    List<XElement> allList = REFs[id];

                    foreach (var innerel in allList)
                    {
                        if (!result.Contains(innerel.Parent))
                        {
                            result.Add(innerel.Parent);

                            level++;
                            getAllUsages(level, maxLevel, innerel.Parent, result);
                        }
                    }
                }
            }
        }


        public IEnumerable<XElement> GetElementsByPath(string path, XElement element)
        {
            if (string.IsNullOrEmpty(path))
                return new XElement[] { element };

            var originalPath = path;


            var elementPath = path;
            var nextPath = "";

           

            if (word.findNonAlphaCommand.IsMatch(path, 1))
            {
                var nonalphaMatch = word.findNonAlphaCommand.Match(path, 1);

                elementPath = originalPath.Substring(0, nonalphaMatch.Index);
                nextPath = originalPath.Substring(nonalphaMatch.Index, originalPath.Length - nonalphaMatch.Index);
            }


            if (elementPath.StartsWith("childs") || elementPath.StartsWith("$childs"))
            {
                var id = element.Attribute("id").Value;

                if (REFs.ContainsKey(id))
                {
                    List<XElement> allList = REFs[id];

                    List<XElement> filteredList = allList.Where(x => x.Name == "parent")
                        .Select(x => x.Parent)
                        .Where(x => x.Attribute("id").Value != id).ToList();

                    List<XElement> resultList = new List<XElement>();
                    foreach (var el in filteredList)
                    {
                        foreach (var innerel in GetElementsByPath(nextPath, el))
                        {
                            resultList.Add(innerel);
                        }
                    }

                    resultList = resultList.OrderByDescending(x => getFullName(x)).ToList();

                    return resultList;
                }
            }

            if (elementPath.StartsWith("allchilds"))
            {
                List<XElement> resultList = new List<XElement>();

                getAllUsages(0, 100, element, resultList);

                resultList = resultList.Distinct().ToList();
            }

            if (elementPath.StartsWith("$memberobjects") || elementPath.StartsWith("memberobjects"))
            {
                List<XElement> resultList = new List<XElement>();

                if (element.Elements("members").Count() > 0)
                {

                    foreach (var member in element.Element("members").Elements("member"))
                    {
                        if (member.Attribute("refid") != null)
                        {
                            var refid = member.Attribute("refid").Value;

                            if (IDs.ContainsKey(refid))
                            {
                                var sourceEl = IDs[refid];

                                //filter and remove links

                                var tempResult = new List<XElement>();

                                var partResult = GetElementsByPath(nextPath, sourceEl);

                                foreach(var partel in partResult)
                                {
                                    if (partel.Element("start") != null && partel.Element("end") != null)
                                    {
                                        int ee = 12;
                                    }
                                    else
                                    {
                                        tempResult.Add(partel);

                                    }
                                }

                                resultList.AddRange(tempResult);
                            }
                        }
                    }
                    resultList = resultList.Distinct().ToList();
                    resultList = resultList.OrderByDescending(x => getFullName(x)).ToList();
                }
                return resultList;
            }

            if (elementPath.StartsWith("$members"))
            {
                List<XElement> resultList = new List<XElement>();

                if (element.Elements("members").Count() > 0)
                {

                    foreach (var member in element.Element("members").Elements("member"))
                    {
                        if (member.Attribute("refid") != null)
                        {
                            var refid = member.Attribute("refid").Value;

                            if (IDs.ContainsKey(refid))
                            {
                                var sourceEl = IDs[refid];

                                resultList.AddRange(GetElementsByPath(nextPath, sourceEl));
                            }
                        }
                    }
                    resultList = resultList.Distinct().ToList();
                    resultList = resultList.OrderByDescending(x => getFullName(x)).ToList();
                }
                return resultList;
            }

            if (elementPath.StartsWith("$visiblemembers"))
            {
                List<XElement> resultList = new List<XElement>();

                foreach (var member in element.Element("members").Elements("member"))
                {
                   // var attr = member.Element(XName.Get("visible"));
                    if (member.Element(XName.Get("visible")) != null && member.Element(XName.Get("visible")).Value == "false")
                    {
                        int ee = 12;
                    }
                    else
                    {
                        if (member.Attribute("refid") != null)
                        {
                            var refid = member.Attribute("refid").Value;

                            if (IDs.ContainsKey(refid))
                            {
                                var sourceEl = IDs[refid];

                                resultList.AddRange(GetElementsByPath(nextPath, sourceEl));
                            }
                        }
                    }
                }
                resultList = resultList.Distinct().ToList();
                resultList = resultList.OrderByDescending(x => getFullName(x)).ToList();
                return resultList;
            }

            if (elementPath.StartsWith("$links"))
            {
                List<XElement> resultList = new List<XElement>();

                if (element.Element("start") != null && element.Element("start").Attribute("refid") != null)
                {
                    var refid = element.Element("start").Attribute("refid").Value;

                    if (IDs.ContainsKey(refid))
                    {
                        var sourceEl = IDs[refid];

                        resultList.AddRange(GetElementsByPath(nextPath,sourceEl));
                    }
                }

                if (element.Element("end") != null && element.Element("end").Attribute("refid") != null)
                {
                    var refid = element.Element("end").Attribute("refid").Value;

                    if (IDs.ContainsKey(refid))
                    {
                        var sourceEl = IDs[refid];

                        resultList.AddRange(GetElementsByPath(nextPath,sourceEl));
                    }
                }
                resultList = resultList.Distinct().ToList();
                resultList = resultList.OrderByDescending(x => getFullName(x)).ToList();
                return resultList;
            }

            if (originalPath.StartsWith("+start") || originalPath.StartsWith("$deliverable"))
            {
                int ee = 12;
            }

            if (elementPath.StartsWith("+"))
            {
                var elementName = elementPath.Substring(1, elementPath.Length - 1);



                var id = element.Attribute("id").Value;

                if (REFs.ContainsKey(id))
                {
                    // List<XElement> allList = REFs[id].Select(x=>x.Parent).ToList();
                    List<XElement> allList = REFs[id].ToList();

                    var filteredEl = allList.Where(x => x.Name == elementName).ToList();

                    List<XElement> resultList = new List<XElement>();

                    foreach (var el in filteredEl)
                    {
                        if (el.Parent.Name.LocalName != "member")
                        {
                            foreach (var innerel in GetElementsByPath(nextPath, el.Parent).Where(x => x.Name.LocalName != "member"))
                            {
                                resultList.Add(innerel);
                            }
                        }
                    }

                    return resultList.Distinct().OrderByDescending(x => getFullName(x)).ToList(); 
                }
                else
                {
                    return new List<XElement>();
                }
            }

            //filter by type
            if (elementPath.StartsWith("$"))
            {
                if (elementPath.StartsWith("$Attributes"))
                {
                    int ee = 12;
                }
                
                var elementName = elementPath.Substring(1, elementPath.Length - 1);

                if (element.Parent.Attribute("label").Value.ToLower() == elementName.ToLower()
                    || element.Parent.Attribute("setLabel").Value.ToLower() == elementName.ToLower()
                    )
                {
                    if (!string.IsNullOrEmpty(nextPath))
                    {

                        List<XElement> resultList = new List<XElement>();


                        foreach (var innerel in GetElementsByPath(nextPath, element))
                        {
                            resultList.Add(innerel);
                        }

                        return resultList;
                    }
                    else
                        return new List<XElement> { element };
                }

                return new List<XElement>();
            }

          

            //filter by element or attribute, return object not reference
            //if element is first after command
            if (elementPath.StartsWith("#") || !elementPath.Contains(" "))
            {
                var elementName = elementPath;

                if(elementPath.StartsWith("#"))
                    elementName = elementPath.Substring(1, elementPath.Length - 1);

                var elementNames = elementName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (var curname in elementNames)
                {
                    var resultList = new List<XElement>();

                    var attElement = element.Element(curname);

                    if (attElement != null)
                    {
                        if (attElement.Attribute("refid") != null)
                        {
                            var refid = attElement.Attribute("refid").Value;

                            var sourceEl = IDs[refid];

                            //return new XElement[] { sourceEl };
                            resultList.Add(sourceEl);
                        }
                    }

                    if (resultList.Count > 0)
                    {
                        if (!string.IsNullOrEmpty(nextPath))
                        {
                            List<XElement> resultList2 = new List<XElement>();
                            foreach (var inn in resultList)
                            {
                                foreach (var innerel in GetElementsByPath(nextPath, inn))
                                {
                                    if (nextPath.StartsWith("$Attributes"))
                                    {
                                        int eeii = 12;
                                    }

                                    resultList2.Add(innerel);
                                }
                            }

                            return resultList2.Distinct();
                        }
                        else
                            return resultList.Distinct();
                    }
                }

            }

            //return by label type
            if (element.Parent.Name.LocalName.ToLower() == "cif")
            {
                var tempList = getBySetLabel(elementPath);

                if (!string.IsNullOrEmpty(nextPath))
                {
                    List<XElement> resultList = new List<XElement>();

                    foreach (var curinnel in tempList)
                    {
                        foreach (var innerel in GetElementsByPath(nextPath, curinnel))
                        {
                            resultList.Add(innerel);
                        }
                    }

                    return resultList;
                }

                return tempList;
            }
            //verify if is possible return default or retun empty list
            //return new XElement[] { element };
            return new List<XElement>();
        }

        public string GetAttributeValue(string attributeName, XElement element)
        {
            var originalAttributeName = attributeName;

            attributeName = attributeName.ToLower();

            //select attribute name and separe path before attribute
            string attribPath = "";

            //neded for find 
            if (word.findSeparator.IsMatch(attributeName))// && (attributeName.StartsWith("#") || attributeName.StartsWith("$")))
            {
                string[] attribParts = word.findSeparator.Split(attributeName)
                    .Where(x => !string.IsNullOrEmpty(x)).ToArray();

                //attribute name
                attributeName = attribParts[attribParts.Length - 1];

                //new path
                attribPath = originalAttributeName.Substring(0, originalAttributeName.Length - attributeName.Length - 1);
            }

            if (!string.IsNullOrEmpty(attribPath))
            {
                var els = GetElementsByPath(attribPath, element).ToList();

                //select new element for attribute value;
                //element = new element current

                if (els.Count > 0)
                {
                    int ee = 12;

                    var attribvalue = GetAttributeValue(attributeName, els.First());

                    return attribvalue;
                }
                else
                {
                    if(originalAttributeName.Contains("datatype#name") || originalAttributeName == "datatype#name")
                        return "undefined";
                }
            }



            //if (attributeName.StartsWith("+"))
            //{
            //    var attriPath = attributeName.Substring(1,attributeName.Length - 1);

            //    if (word.findNonAlpha.IsMatch(attriPath))
            //    {
            //        if (attriPath.Contains("#"))
            //        {
            //            int pos = attriPath.IndexOf("#");
            //            string elementName = attriPath.Substring(0, pos);
            //            string otherPath = attriPath.Substring(pos + 1, attriPath.Length - pos - 1);

            //            var id = element.Attribute("id").Value;

            //            if (REFs.ContainsKey(id))
            //            {
            //                List<XElement> allList = REFs[id];

            //                var filteredEl = allList.Where(x => x.Name == elementName)
            //                .Select(x => x.Parent)
            //                .FirstOrDefault();

            //                if (filteredEl != null)
            //                {
            //                    return GetAttributeValue(otherPath, filteredEl);
            //                }
            //            }
            //        }
            //        return "undefined link";
            //    }
            //    else
            //    {
            //        var id = element.Attribute("id").Value;

            //        //if (id == "210545")
            //        //{
            //        //    int ee = 12;
            //        //}

            //        if (REFs.ContainsKey(id))
            //        {
            //            List<XElement> allList = REFs[id];

            //            var filteredEl = allList.Where(x => x.Name == attriPath)
            //            .Select(x => x.Parent)
            //            .FirstOrDefault();

            //            if (filteredEl != null)
            //                return GetAttributeValue("image", filteredEl);
            //        }
            //        return "";//not found
            //    }
            //}

            //if (attributeName.Contains("#"))
            //{
            //    int pos = attributeName.IndexOf("#");
            //    string elementName = attributeName.Substring(0, pos);
            //    string otherPath = attributeName.Substring(pos + 1, attributeName.Length - pos - 1);



            //    var attElement = element.Element(elementName);

            //    if (attElement != null)
            //    {
            //        if (attElement.Attribute("refid") != null)
            //        {
            //            var refid = attElement.Attribute("refid").Value;

            //            var refEl = IDs[refid];

            //            return GetAttributeValue(otherPath, refEl);
            //        }

            //        return GetAttributeValue(otherPath, attElement);
            //    }
            //    return "undefined element - object";
            //}

            if (attributeName == "type")
            {
                var parent = element;
                while (parent != null)
                {
                    if (parent.Attribute("label") != null)
                        return parent.Attribute("label").Value;

                    parent = parent.Parent;
                }
            }

            if (attributeName == "modifytime")// && element.Name == "notebook")
            {
               // return this.modifyTime.ToLongDateString();
                return this.modifyTime.ToString(DateFormat);
            }

            if (attributeName == "id")// && element.Attribute("name").Value.ToLower().Contains("new pub"))
            {
                var testpath = "+end$Parent/Child Link#start+core";
                
                if (element.Attribute("id").Value == "1000023248")
                {
                    int ee = 12;                  

                    var datares = GetElementsByPath(testpath, element);
                }
                
               
                var numbering = "";

                if (element != null && element.Element("numberPrefix") != null)
                {
                    var parent = element;

                    while (parent != null && parent.Element("numberPrefix") != null)
                    {
                        if (string.IsNullOrEmpty(numbering))
                            numbering = numberPrefix(parent);
                        else
                            numbering = numberPrefix(parent) + "." + numbering;

                        if (numbering == ".3.2")
                        {
                            int ee = 12;
                            //vyhladavanie organization parenta
                        }


                        if (parent.Element("parent") != null)
                        {
                            var refid = parent.Element("parent").Attribute("refid").Value;
                            parent = IDs[refid];
                        }
                        else
                            parent = null;

                    
                    }
                }

              

                return numbering;
            }

            if (attributeName == "cid")// && element.Attribute("name").Value.ToLower().Contains("new pub"))
            {
                var testpath = "+end$Parent/Child Link#start+core";

                if (element.Attribute("id").Value == "1000023248")
                {
                    int ee = 12;

                    var datares = GetElementsByPath(testpath, element);
                }


                var numbering = "";
             
                if (GetElementsByPath(testpath, element).Count() > 0)
                {
                    if (element.Attribute("id").Value == "1000023248")
                    {
                        int ee = 12;
                    }

                    var curElement = element;

                    while (curElement != null)
                    {
                        if (string.IsNullOrEmpty(numbering))
                            numbering = numberPrefix(curElement);
                        else
                            numbering = numberPrefix(curElement) + "." + numbering;

                        if (GetElementsByPath(testpath, curElement).Count() > 0)
                        {

                            curElement = GetElementsByPath(testpath, curElement).First();
                        }
                        else
                            curElement = null;
                    }
                }

                return numbering;
            }

           

            if (attributeName == "fullname")// && element.Attribute("name").Value.ToLower().Contains("new pub"))
            {
                var parent = element;
                var numbering = "";

                while (parent != null && parent.Element("numberPrefix") != null)
                {
                    if (string.IsNullOrEmpty(numbering))
                        numbering = numberPrefix(parent);
                    else
                        numbering = numberPrefix(parent) + "." + numbering;

                    if (parent.Element("parent") != null)
                    {
                        var refid = parent.Element("parent").Attribute("refid").Value;
                        parent = IDs[refid];
                    }
                    else
                        parent = null;
                }

                return numbering + " " + element.Attribute("name").Value;
            }

            if (attributeName == "oid" && element.Attribute("id") != null)
                return element.Attribute("id").Value;


            //custom property could contains spaces in name
            //custom property, find by name

            if (element.Element("customProperties") != null)
            {
                if (attributeName != "name")
                {
                    int ee = 12;
                }
                var customProperties = element.Element("customProperties");

                var customElement = customProperties.Elements("customProperty").Where(x => x.Attribute("name") != null && x.Attribute("name").Value.ToLower() == attributeName).FirstOrDefault();

                if (customElement != null)
                {
                    var resvalue = customElement.Element("value").Value;

                    //typref
                    if (string.IsNullOrEmpty(resvalue) && customElement.Attribute(XName.Get("typref")) != null)
                    {
                        //get default value
                        var refTypeValue = customElement.Attribute(XName.Get("typref")).Value;
                        var defTypeValue = IDs[refTypeValue];

                        if (defTypeValue != null && defTypeValue.Element(XName.Get("default")) != null)
                        {
                            resvalue = defTypeValue.Element(XName.Get("default")).Value;
                        }
                    }

                    return resvalue;
                }
                else
                {
                    //find in definitions
                    //notebook/types/customConfigurations/customConfiguration/objectTypes/objectType

                    var elementName = element.Name.LocalName;

                    var objectType = this.Notebook
                        .Element(XName.Get("types"))
                        .Element(XName.Get("customConfigurations"))
                        .Element(XName.Get("customConfiguration"))
                        .Element(XName.Get("objectTypes"))
                        .Elements(XName.Get("objectType"))
                        .Where(x => x.Attribute(XName.Get("name")).Value == elementName).FirstOrDefault();

                    foreach (var customTypes in objectType.Element(XName.Get("customPropertyTypes")).Elements(XName.Get("customPropertyType")))
                    {
                        var refTypeID = customTypes.Attribute(XName.Get("refid")).Value;

                        var defTypeValue = IDs[refTypeID];

                        if(attributeName == defTypeValue.Attribute(XName.Get("name")).Value.ToLower())
                        {
                            if (defTypeValue.Element(XName.Get("default")) != null)
                            {
                                return defTypeValue.Element(XName.Get("default")).Value;
                            }
                        }
                    }

                   
                }
            }



            //if attribute contains non alpha chars
            if (word.findNonAlphaNonSpace.IsMatch(attributeName))
            {
                ReportEngine.LogBuilder.AppendLine("Property does not exists:" + attributeName);

                //resolve nearest name

                string nearestName = word.findNonAlphaNonSpace.Replace(attributeName, "");

                if (element.Attribute(nearestName) != null)
                {
                    ReportEngine.LogBuilder.AppendLine("Replaced with:" + nearestName);

                    return element.Attribute(nearestName).Value;
                }

                if (element.Element(nearestName) != null)
                {
                    ReportEngine.LogBuilder.AppendLine("Replaced with:" + nearestName);
                 
                    return element.Element(nearestName).Value;
                }


                return string.Empty;
            }

            

            if (element.Attribute(attributeName) != null)
                return element.Attribute(attributeName).Value;

            if (element.Element(attributeName) != null)
                return element.Element(attributeName).Value;

            //validate lowered names

            if (element.Attributes().Where(x=>x.Name.LocalName.ToLower() == attributeName).FirstOrDefault() != null)
                return element.Attributes().Where(x => x.Name.LocalName.ToLower() == attributeName).FirstOrDefault().Value;

            if (element.Elements().Where(x => x.Name.LocalName.ToLower() == attributeName).FirstOrDefault() != null)
                return element.Elements().Where(x => x.Name.LocalName.ToLower() == attributeName).FirstOrDefault().Value;

            return string.Empty;
        }

        public string getTypeName(XElement element)
        {
            var parent = element;
            while (parent != null)
            {
                if (parent.Attribute("label") != null)
                    return parent.Attribute("label").Value;

                parent = parent.Parent;
            }

            return "undefined";

        }

        public string getFullName(XElement element)
        {
            var parent = element;
            var numbering = "";

            while (parent != null && parent.Element("numberPrefix") != null)
            {
                if (string.IsNullOrEmpty(numbering))
                    numbering = numberPrefix(parent);
                else
                    numbering = numberPrefix(parent) + "." + numbering;

                if (parent.Element("parent") != null)
                {
                    var refid = parent.Element("parent").Attribute("refid").Value;
                    parent = IDs[refid];
                }
                else
                    parent = null;
            }

            if (string.IsNullOrEmpty(numbering))
                numbering = element.Attribute("name").Value;

            return numbering + " " + element.Attribute("name").Value;
        }

        public static string numberPrefix(XElement element)
        {
            if (element.Element("numberPrefix") != null)
            {
                string numValue = element.Element("numberPrefix").Value;

                string prefixStyle = element.Element("prefixStyle").Value;

                if (numValue == "9991")
                {
                    int ee = 12;
                }

                if (prefixStyle == "numeric")
                    return numValue;

                if (prefixStyle == "alphaExtended")
                {
                    if (Int64.Parse(numValue) >= 0)
                    {
                        var totalVal = Int64.Parse(numValue);

                        var currentVal = totalVal;

                        var resText = "";

                        if (totalVal == 70)
                        {
                            int ee = 12;
                        }

                        while (currentVal > 24)
                        {
                            var zvysok = currentVal % 26;
                            var podiel = (currentVal - zvysok) / 26;

                            byte curByte = (byte)zvysok;
                            curByte += (byte)'A' - 1;
                            char curChar = (char)curByte;

                            resText = curChar.ToString() + resText;

                            currentVal = podiel;
                        }


                        byte lastByte = (byte)currentVal;
                        lastByte += (byte)'A' - 1;
                        char lastChar = (char)lastByte;

                        resText = lastChar.ToString() + resText;


                        return resText;


                        //byte bv = byte.Parse(numValue);
                        //bv += (byte)'A' - 1;

                        //if (bv > 35 && bv < 122)
                        //{
                        //    char chv = (char)bv;

                        //    //if (chv.ToString() != "M" && chv.ToString() != "C")
                        //    //{
                        //    //    int ee = 12;
                        //    //}

                        //    return chv.ToString();
                        //}
                        //else
                        //    return "A." + numValue;
                    }
                }


            }

            return "";
        }
    }

}
